open Ast_TablePro
open Printer
open Tableutil


let rec runprogram program  sourcefile=
 
let rec run locals globals functions env currfname statements = 
         
	 (*print_endline (string_of_bool env); print_endline (string_of_int (List.length statements));*)
 	 let rec eval (locals, globals, functions, env) = function
	 			      Literal(n) -> (F(n)) , (locals, globals, functions, env)
				     | Binop (e1 , op , e2) ->
					 let val1, (locals, globals, functions, env)  = eval (locals, globals, functions, env) e1 
						in
							let val2, (locals, globals, functions, env)  = eval (locals, globals, functions, env) e2 
							in
								let boolean i = if i then 1.0 else 0.0
								in 
									let v =
									(match (op , val1 , val2) with 
										 (Add , F f1 , F f2) -> F(f1 +. f2)
										 | (Sub , F f1 , F f2) -> F(f1 -. f2)
										 | (Mult , F f1 , F f2) -> F(f1 *. f2)
										 | (Div , F f1 , F f2) -> 
										   if int_of_float f2 = 0 then	
										   	raise (Failure("Divide by Zero"))
										   else
										 	F(f1 /. f2)
										 | (Greater , F f1 , F f2) -> F (boolean((f1> f2)))
										 | (Less , F f1 , F f2) -> F (boolean((f1< f2)))
										 | (Equality, F f1 , F f2) -> F (boolean((f1 = f2)))
										 | (Or, _, _) -> raise (Failure("Or not supported"))		   
										  | (And, _, _) -> raise (Failure("Or not supported"))		   
										  | (_, _, _) -> raise (Failure("Multiple binary combination or identifier not initialized"))		   	 
										
									) 
									
									in v , (locals, globals, functions, env)
									
				    | IndexRange (col, ste, ene , op, e1) -> 
				    				                        let st =
				    				                           let evst,(locals, globals, functions, env) = eval(locals, globals, functions, env)  ste in
				    							   (match evst with F f -> int_of_float f
				    										| _ -> raise(Failure("Range start index expression not a number")) )
				    				                        in
				    				                        let en =
				    				                           let even,(locals, globals, functions, env) =  eval(locals, globals, functions, env)  ene in
				    							   (match even with F f -> int_of_float f
				    										| _ -> raise(Failure("Range end index expression not a number")) )
				    				                        
				    				                        in
				    				     			let rhsVal, (locals, globals, functions, env) = eval (locals, globals, functions, env) e1
				    				     			in
				    							       let rec performloop  currIndex looplocals loopglobals =
				    								 let assign   aindex =
				    									  let declList = 
				    									     if (NameMap.mem col looplocals) then (NameMap.find col looplocals)
				    									     else if (NameMap.mem col loopglobals) then (NameMap.find col loopglobals)
				    									     else raise (Failure ("Id not found")) 
				    									   in 
				    								 	   let colList = declList.vVal in 
				    								  (match colList with
				    								   FLi fl -> let res =  
				    										 (match rhsVal with 
				    											F f -> let colArray =Array.of_list fl
				    											       in 
				    											       let val1 = F (colArray.(aindex)) in
				    												let valAssign = 
				    													(match (op , val1 , rhsVal) with 
				    														(Add , F f1 , F f2) -> (f1 +. f2)
				    														| (Sub , F f1 , F f2) -> (f1 -. f2)
				    														| (Mult , F f1 , F f2) -> (f1 *. f2)
				    														| (Div , F f1 , F f2) -> 
				    														if int_of_float f2 = 0 then	
																		  	raise (Failure("Divide by Zero"))
																		  else
										 								(f1 /. f2)
				    														| (_, _, _) -> raise (Failure("Binop combination not supported"))		   	 
				    													) 
				    												in
				    												let replaceList  = ignore(colArray.(aindex) <- valAssign); FLi(Array.to_list  colArray)
				    												 in
				    													  if (NameMap.mem col looplocals) then 
				    														  let localsadded = NameMap.add col ({vname= declList.vname ;vtype= declList.vtype; vVal= replaceList}) looplocals
				    														  in (localsadded , loopglobals)
				    													  else if (NameMap.mem col loopglobals) then 
				    														  let globalsadded = NameMap.add col ({vname= declList.vname ;vtype= declList.vtype; vVal= replaceList}) loopglobals
				    														  in (looplocals , globalsadded)
				    													  else raise (Failure ("undeclared identifier"))
				    											|   _ -> raise ( Failure ("Incompatible assignment for index range"))
				    										 )
				    									     in res
				    								   | _ -> raise (Failure ("Not the right type"))
				    								   )
				    								   in  
				    								     
				    								     if currIndex <= en then 
				    								             let  (al, ag) = assign currIndex
				    								             in let currIndex = currIndex+1
				    								             in performloop  currIndex al ag
				    								     else 
				    								             (looplocals, loopglobals)
				    						           	    in  
				    						           		let (l, g) = performloop st locals globals 
				    						           		in rhsVal, (l, g, functions, env) 
				    				     			    
				     
				     			    
				     
				     | IndexAsn (id, e1,e2) ->   let ev,(locals, globals, functions, env)= eval(locals, globals, functions, env)  e2 			
				     					 in
									 let ev1,(locals, globals, functions, env) =  eval(locals, globals, functions, env)  e1 
									 in
									 let v1 = 
									  (match ev1 with F f -> int_of_float f
										   | _ -> raise(Failure("Index expression not a number"))
									   )
									 in
									  let declList = 
									     if (NameMap.mem id locals) then (NameMap.find id locals)
									     else if (NameMap.mem id globals) then (NameMap.find id globals)
									     else raise (Failure ("Id not found")) 
									   in 
				     			  		 let colList = declList.vVal 
							  		 in 
							  		 let colListlen =
							  		 (match colList with
							  		 	FLi fl->List.length fl
							  		 	| SLi sl ->List.length sl
							  		 	| _ -> raise (Failure ("Cannot determine length of this retVal"))
							  		 )
							  		 in
								         let appendNew =
								       		let newCollist =
										       (match colList with
													FLi fl ->(match ev with 
															F f -> FLi(fl @ [f])
															| _ -> raise (Failure ("Incomaptible assignment"))
														  )
													| SLi sl ->(match ev with 
															S s -> SLi(sl @ [ s ])
															| _ -> raise (Failure ("Incomaptible assignment"))
														   )
															
													| _ -> raise (Failure ("Not the right type"))
											)in
										  if (NameMap.mem id locals) then 
										  let localsadded = NameMap.add id ({vname= declList.vname ;vtype= declList.vtype; vVal= newCollist}) locals
										  in (localsadded , globals)
										  else if (NameMap.mem id globals) then 
										  let globalsadded = NameMap.add id ({vname= declList.vname ;vtype= declList.vtype; vVal= newCollist}) globals
										  in (locals , globalsadded)
										  else raise (Failure ("Id not found"))
								         in
							  		let (new_locals, new_globals) = 
							  		 if v1 = colListlen then 
							  		   appendNew
							  		    
							  		 else if v1 < colListlen then
											 let assign  = (match colList with
													FLi fl -> let res =  
														 (match ev with 
															F f -> let colArray =Array.of_list fl
															       in 
																 let replaceList  = ignore(colArray.(v1) <- f); FLi(Array.to_list  colArray)
																 in
																	  if (NameMap.mem id locals) then 
																		  let localsadded = NameMap.add id ({vname= declList.vname ;vtype= declList.vtype; vVal= replaceList}) locals
																		  in (localsadded , globals)
																	  else if (NameMap.mem id globals) then 
																		  let globalsadded = NameMap.add id ({vname= declList.vname ;vtype= declList.vtype; vVal= replaceList}) globals
																		  in (locals , globalsadded)
																	  else raise (Failure ("Id not found"))
															|   _ -> raise ( Failure ("Incompatible assignment for index range"))
														 )
													     in res
													| SLi sl -> let res =  
														 (match ev with 
															S s -> let colArray =Array.of_list sl
															       in 
																 let replaceList  = ignore(colArray.(v1) <- s); SLi(Array.to_list  colArray)
																 in
																	  if (NameMap.mem id locals) then 
																	  let localsadded = NameMap.add id ({vname= declList.vname ;vtype= declList.vtype; vVal= replaceList}) locals
																	  in (localsadded , globals)
																	  else if (NameMap.mem id globals) then 
																	  let globalsadded = NameMap.add id ({vname= declList.vname ;vtype= declList.vtype; vVal= replaceList}) globals
																	  in (locals , globalsadded)
																	  else raise (Failure ("Id not found"))
															|  _ -> raise ( Failure ("Incompatible assignment for index range"))
														 )
													     in res


													| _ -> raise (Failure ("Not the right type"))
												   )
										       in  assign 
				     			    	      else raise (Failure ("index id out of range" ))
				     				in ev, (new_locals, new_globals, functions, env)
				     
				     | Assign(id, e1) -> let ev,(locals, globals, functions, env)= eval(locals, globals, functions, env)  e1 
				     			in
				     			if NameMap.mem id locals then 
				     				let declis = (NameMap.find id locals)
				     				in
				     				(match declis.vtype with
				     				Num -> (match ev with
				     					F f -> 
				     					       ev, (  (NameMap.add id ({vname= declis.vname ;vtype= declis.vtype; vVal= ev}) locals ), globals, functions, env) 
				     					| _ -> raise (Failure (" Types not compatible in assignment,Expected Number type"))
				     					)
				     				| Str ->(match ev with
				     					S s -> ev, ((NameMap.add id ({vname= declis.vname ;vtype= declis.vtype; vVal= ev}) locals), globals, functions, env) 
				     					| _ -> raise (Failure (" Types not compatible in assignment, Expected String type"))
				     					)
				     				| Col c ->( match c.colContentType with
									   Num -> (match ev with
											FLi fl -> ev, ((NameMap.add id ({vname= declis.vname ;vtype= declis.vtype; vVal= ev}) locals), globals, functions, env) 
											| _ -> raise (Failure (" Types not compatible in assignment, Expected Number column"))
									           )
									   | Str -> (match ev with
											SLi sl -> ev, ((NameMap.add id ({vname= declis.vname ;vtype= declis.vtype; vVal= ev}) locals), globals, functions, env) 
											| _ -> raise (Failure (" Types not compatible in assignment, Expected String column"))
									           )
				     					   | _ -> raise (Failure (" Types not compatible in assignment"))									           
				     					  )
				     				)
				     				
				     				 
				     			else if NameMap.mem id globals then
				     				let declis = (NameMap.find id globals)
				     				in
				     				(match declis.vtype with
				     				
				     				Num -> (match ev with
				     					F f -> ev, (locals , (NameMap.add id ({vname= declis.vname ;vtype= declis.vtype; vVal= ev}) globals), functions, env) 
				     					| _ -> raise (Failure (" Types not compatible in assignment, expected number type"))
				     					)
				     				| Str ->(match ev with
				     					S s -> ev, (locals , (NameMap.add id ({vname= declis.vname ;vtype= declis.vtype; vVal= ev}) globals), functions, env) 
				     					| _ -> raise (Failure (" Types not compatible in assignment,expected string type"))
				     					)
				     				| Col c ->( match c.colContentType with
									   Num -> (match ev with
											FLi fl -> ev, (locals , (NameMap.add id ({vname= declis.vname ;vtype= declis.vtype; vVal= ev}) globals), functions, env) 
											| _ -> raise (Failure (" Types not compatible in assignment,expected number column"))
									           )
									   | Str -> (match ev with
											SLi sl -> ev, (locals , (NameMap.add id ({vname= declis.vname ;vtype= declis.vtype; vVal= ev}) globals), functions, env) 
											| _ -> raise (Failure (" Types not compatible in assignment,expected string column"))
									           )
				     					   | _ -> raise (Failure (" Types not compatible in assignment"))									           
				     					  )
				     					
				     				)
				      			else raise (Failure("Identfier not declared" ^id ))

				     | IntLiteral (e1) -> F(float_of_int e1) ,(locals, globals, functions, env)
				     
				     | Id (id) -> 
				     	
				     	let declList = 
						if (NameMap.mem id locals) then (NameMap.find id locals)
						else if (NameMap.mem id globals) then (NameMap.find id globals)
						else raise (Failure ("Id not declared")) 
					in 
					    declList.vVal , (locals, globals, functions, env)

				     | StrLiteral (e1) -> S(e1) ,(locals, globals, functions, env)
				     | Index (id, e1) ->  let ev,(locals, globals, functions, env)= eval(locals, globals, functions, env)  e1 
								   in 
									let mval =  (match ev with
											   F f -> int_of_float f
											   | _  -> raise (Failure ("Index is not a number" )) 
											  )
										      in
										      let declist = 
										 		if NameMap.mem id locals then 
												(NameMap.find id locals)
										            else if NameMap.mem id globals then 
												(NameMap.find id globals)
												else raise (Failure ("column index not found" )) 
											in
											let v =
											(match (declist.vVal) with
											 FLi f1 -> let arr = Array.of_list f1 
												    in F(arr.(mval))
												    
			    								 |SLi s1 -> let arr = Array.of_list s1 
												    in S(arr.(mval))

											 | _ -> raise (Failure ("Not a column type"))

											)

									 in v,(locals, globals, functions, env)
				     | IndexSize (id) -> let declList = 
								if (NameMap.mem id locals) then (NameMap.find id locals)
								else if (NameMap.mem id globals) then (NameMap.find id globals)
								else raise (Failure ("Id not declared")) 
								in 
					   let colList = declList.vVal 
					   in 	
					   let colListlen =
					   		(match colList with
					   			FLi fl->List.length fl
					   			| SLi sl ->List.length sl
					   			| _ -> raise (Failure ("Cannot determine length of this retVal"))
					   			)
						in
					   F(float_of_int colListlen),(locals, globals, functions, env)
	 		| Call(f, elist) ->
	 				  let fdecl =
	 				  	(*ignore(print_string "Inside Call"); ignore(Printer.print_functions functions); ignore(print_string f);*)
	 				  	(*if NameMap.mem f functions then ignore (print_string "true") else ignore (print_string "false");*)
	 				        try NameMap.find f functions
	 				    with Not_found -> raise (Failure ("undefined function " ^ f))
	 				  	in
	 				  	let slist = fdecl.body
	 				  	 in
	 				  	       (* merge arguments, formals into a new locals map to be sent to the function *)
	 				  	      let fargtype formal = 
	 				  	       ( match formal with 
	 				  	          Sarg(x, y) -> vdecl_from_str (x)
	 				  	          | Carg (p,q,r,s)->
	 				  	          let conttype = vdecl_from_str (r)
							  in
	 				  		     Col ({colName=s; colContentType=conttype})
	 				  	       )
						      in
						      let fargname formal = 
	 				  	       (match formal with
	 				  	          Sarg(x, y) ->  (y)
	 				  	          | Carg(p, q, r, s) ->  (q)
	 				  	       )
						      in
					              let evalex ex =
					                   let evalres , (locals , globals, functions, env) = eval (locals, globals, functions, env) ex
					                   in evalres
						      in
	 				  	      let fargdeclList =
							       let fargdecl l e f =
								   ({vname=(fargname f);vtype=(fargtype f);vVal= evalex e})::l
	 				  	        in List.fold_left2 fargdecl [] elist fdecl.formals
	 				  	       in
	 				  	       let initialfunclocals =
	 				  	          let oneformaladdedmap  argsmap fargdecl=
	 				  	            NameMap.add fargdecl.vname fargdecl argsmap
	 				  	        in 
		 				  	       try List.fold_left oneformaladdedmap NameMap.empty  fargdeclList
							       with Invalid_argument(_) ->
							       raise (Failure ("wrong number of arguments passed to " ^ fdecl.fname))
	 				  	        
	 				  	        in
	 				  	  	let (_, globals, functions, _) = run initialfunclocals globals functions true f slist
	 				  	  	in 
	 				  	  	let fd = NameMap.find f functions
	 				  	  	 in   fd.retValue ,(locals, globals, functions, env)
	 				  	  	
								in
	  						  	let rec  exec_stmnt (locals, globals, functions, env, currfname) = function
	    							  Block(slist) ->  List.fold_left exec_stmnt ( locals, globals, functions, env, currfname) slist   
	    							| SDeclstmnt(s1 ,s2) -> (* populate symbol table *)
	    								
										if( env ) then
											let new_locals =
											if NameMap.mem s2 locals then raise (Failure "Redefined Identifier") 
											else NameMap.add s2 ({vname=s2 ; vtype= (vdecl_from_str s1);  vVal=S("0")}) locals
											in  (new_locals, globals, functions, env, currfname) 
										else 
											let new_globals = 
											if NameMap.mem s2 globals then raise (Failure "Redefined Identifier") 
											else NameMap.add s2 ({vname=s2 ; vtype=(vdecl_from_str s1);vVal=S("0")})  globals 
											in  (  locals, new_globals, functions, env, currfname)
											
	    							| CDeclstmnt(s1 ,s2, s3, s4) ->(* populate symbol table *)
	    								(*print_string "CDeclStmnt in "; print_endline(string_of_bool env );print_locals locals ; print_globals globals;*)
	    								        let conttype = vdecl_from_str s2
	    								        in
	    								        let contLi =
	    								        (match conttype with
	    								         Str -> SLi([])
	    								         | Num -> FLi([])
	    								         | _ -> raise (Failure ("Content type not supported"))
	    								        )
	    								        in
										if( env ) then
											let new_locals =
											if NameMap.mem s4 locals then raise (Failure "Redefined Identifier") 
											else NameMap.add s4 ({vname=s4 ; vtype= (Col ({colName=s3; colContentType= conttype}));  vVal=contLi}) locals
											in  (new_locals, globals, functions, env, currfname) 
										else 
											let new_globals = 
											if NameMap.mem s4 globals then raise (Failure "Redefined Identifier") 
											else NameMap.add s4 ({vname=s4 ; vtype= (Col ({colName=s3; colContentType= conttype}));  vVal=contLi})  globals 
											in  (  locals, new_globals, functions, env, currfname)
											
								| CStrdeclAsnstmnt(s1,s2,s3,s4,l) ->
									if ((vdecl_from_str s2) != Str ) then raise (Failure ("String list assigned to non str content column" ))
									else
									if( env ) then
									let new_locals =
									if NameMap.mem s4 locals then raise (Failure "Redefined Identifier") 
									else NameMap.add s4 ({vname=s4 ; vtype= (Col ({colName=s3; colContentType= (vdecl_from_str s2)}));  vVal=SLi(l)}) locals
							    		in  (new_locals, globals, functions, env, currfname) 
										else 
										let new_globals = 
										if NameMap.mem s4 globals then raise (Failure "Redefined Identifier") 
											else NameMap.add s4 ({vname=s4 ; vtype= (Col ({colName=s3; colContentType= (vdecl_from_str s2)}));  vVal=SLi(l)})  globals 
											in  (  locals, new_globals, functions, env, currfname)
									
								| CNumdeclAsnstmnt(s1,s2,s3,s4,l) -> 
										if ((vdecl_from_str s2) != Num ) then raise (Failure ("String list assigned to non str content column" ))
										else
											if( env ) then
												let new_locals =
												if NameMap.mem s4 locals then raise (Failure "Redefined Identifier") 
												else NameMap.add s4 ({vname=s4 ; vtype= (Col ({colName=s3; colContentType= (vdecl_from_str s2)}));  vVal=FLi(l)}) locals
												in  (new_locals, globals, functions, env, currfname) 
											else 
												let new_globals = 
												if NameMap.mem s4 globals then raise (Failure "Redefined Identifier") 
												else NameMap.add s4 ({vname=s4 ; vtype= (Col ({colName=s3; colContentType= (vdecl_from_str s2)}));  vVal=FLi(l)})  globals 
												in  (  locals, new_globals, functions, env, currfname)
																
	    							|   Func_decl (name, flist, rettype, slist) -> 
	    							        let retVal =
	    							        (match rettype with
	    							           Sret(s) -> let ret_t = vdecl_from_str s in
	    							           	      (match ret_t with
	    							           	        Str -> S("")
	    							           	        | Num -> F(0.0)
	    							           	        | _ -> raise (Failure ("Return type not recognized"))
	    							           	       )
	    							           | Cret(c, content_s) -> let content_t = vdecl_from_str content_s in
	    							           	        (match content_t with
	    							           	        Str -> SLi([])
	    							           	        | Num -> FLi([])
	    							           	        | _ -> raise (Failure ("Return type not recognized"))
	    							           	        ) 
	    							                      
	    							        )
	    							        in
	    							        let ret_t  =
	    							        (match rettype with
	    							           Sret(s) -> vdecl_from_str s 
	    							           | Cret(c, content_s) -> Col ({colName ="" ; colContentType=vdecl_from_str content_s })
	    							        )
	    							        in
	    								let fdecl = {fname = name; formals = flist; retType = ret_t; body = slist; retValue=retVal}
	    								in
	    								let new_functions =
	    									if NameMap.mem name functions then raise (Failure "Redefined function name") 
	    									else NameMap.add name fdecl functions
	    									in (*ignore(Printer.print_functions new_functions);*)
	    									( locals, globals, new_functions, env, currfname)
	    
	    							|   Stmnt(e) -> 
	    									let v, (locals, globals, functions, env) = eval (locals, globals, functions, env)  e 
	    									in  (locals, globals, functions, env, currfname)
	    							
	    									
	    				
	    							| Loop (e, slist) -> 
										    
										    let rec loop locals globals functions env currfname slist e =
										    let  v, (locals, globals, functions, env)  = eval (locals, globals, functions, env) e in
										    
										    (match v with
										           F f  ->     if f <> 0.0 then  
										                             let ( locals, globals, functions, env, currfname)  =   List.fold_left exec_stmnt  ( locals, globals, functions, env , currfname) slist
										                             in  loop  locals globals functions env currfname slist e
		    											else ( locals, globals, functions, env, currfname) 
		    											
		    									   | _ ->
		    									   	raise (Failure ("Loop Expression not evaluating to number "))
		    								     )
		    								     in loop locals globals functions env  currfname slist e
		    								     
		    							
		    						| Return (s) -> 
		    								if (s != "") then
		    								let retValue =
		    									if NameMap.mem s locals then
												(NameMap.find s locals).vVal
											else if NameMap.mem s globals then
												(NameMap.find s globals).vVal
											else raise (Failure ("undeclared identifier " ^ s))
												in
													let ofdecl = NameMap.find currfname functions
													in
													let new_functions = NameMap.add ofdecl.fname ({fname = ofdecl.fname; formals = ofdecl.formals; retType = ofdecl.retType; body = ofdecl.body; retValue=retValue;}) functions
													in
														( locals, globals, new_functions, env, currfname)
										else
										let retValue = S("")
												in
													let ofdecl = NameMap.find currfname functions
													in
													let new_functions = NameMap.add ofdecl.fname ({fname = ofdecl.fname; formals = ofdecl.formals; retType = ofdecl.retType; body = ofdecl.body; retValue=retValue;}) functions
													in
														( locals, globals, new_functions, env, currfname)


		    							
		    						| If (e, slist1, slist2) -> 
		    						
		    								    let v, (locals, globals, functions, env) = eval (locals, globals, functions, env) e in
		    								    
		    								    (match (v) with
										           ( F f ) -> 
													if f <> 0.0 then (List.fold_left exec_stmnt  ( locals, globals, functions, env, currfname) slist1 )
													else (List.fold_left exec_stmnt  ( locals, globals, functions, env, currfname) slist2)
		    									   | _ ->
		    									   	raise (Failure ("If expression not evaluating to number "))
		    									   	
		    									   
		    								     )													
		    							
		    						| GenerateStmnt (slist) -> (*print_globals globals;print_string "generate statement";*)
									if (String.compare "main" currfname  != 0) then
										raise (Failure ("Generate Statement  allowed in main only" ))
									else
										let checkColType s =
											if ((NameMap.mem s globals)!=true) then
												false
											else if ( (NameMap.find s globals).vtype != Num) then
											  let b =
												if( (NameMap.find s globals).vtype != Str) then
												 true
												else raise (Failure ("Cannot generate table with Num/str type identifier " ^ s))
											  in b
											else raise (Failure ("Cannot generate table with Num/str type identifier " ^ s))
										in	
										    let checked s = checkColType s 
										    in
										        let pickUpColList s = 
												if checked s then
												let list =
												    (match (NameMap.find s globals).vVal with
												    SLi sl -> (*print_string "no converting";List.iter print_string sl;*)
												    		let li =
												    		( match (NameMap.find s globals).vtype with
															Col c -> (c.colName)::sl
															| _ -> raise (Failure ("Cannot generate table with str type identifier " ^ s)) (*To remove warning*)
														)
												    		in li
												    | FLi fl -> 
												    		let li =
														( match (NameMap.find s globals).vtype with
														Col c -> c.colName::(Tableutil.convertFloatListToStringList fl)
														| _ -> raise (Failure ("Cannot generate table with Num type identifier " ^ s)) (*To remove warning*)
														)
														in li

												    | _ -> raise (Failure( "Not a list ")))
												in list
												else raise (Failure ("undeclared identifier list ending with " ^ s))
												 
										 	in
										 	   let addList outerList s = (pickUpColList s)::outerList
										 	   in
										 	      	   let lists = List.fold_left addList [] slist
										 		   in
										 		   	let paddedlists = Tableutil.padLists lists
										 		   	in
										 			   let x = Tableutil.metafoo (List.rev paddedlists) sourcefile
													   in ( locals, globals, functions, env, currfname) 
	    						         
 		
 				in 
 					  let ( locals ,globals, functions, env, currfname) = List.fold_left exec_stmnt ( locals ,globals, functions, env, currfname) statements
 					  
 					  	in ( locals ,globals, functions, env)
 					  	
 					  		in  
 					  			let ( locals ,globals, functions, env) =  try run NameMap.empty NameMap.empty NameMap.empty false "main" program
								with Not_found -> raise (Failure ("Could not run Program"))
								in ( locals ,globals, functions, env);
 					  	